<?php
class YYK{
	/*核心框架存放路径*/
	private static $YYK_path="";

	/*当前应用存放路径*/
	public static $APP_path="";

	/*当前应用入口URL*/
	public static $APP_url="";

	/*配置信息*/
	public static $config;

	/*当前访问的控制器和方法名*/
	public static $ctrlName;
	public static $methodName;

	public static $debug;
	public static $defaultLang="";

	/**
	* 系统入口
	* 并且支持配置自动加载路径
	* @return void
	*/
	public static function start($appDirectory,$conf='config.php', $debug=false){
		//var_dump( $_SERVER);
		// 设定错误和异常处理
		//register_shutdown_function(array('YYK','fatalError'));
		self::$debug = $debug;
		set_error_handler(array('YYK','appError'), E_ALL);
		set_exception_handler(array('YYK','appException'));
		//取当前框架路径
		self::$YYK_path = pathinfo(__FILE__, PATHINFO_DIRNAME);
		//取当前项目路径
		self::$APP_path = realpath( $appDirectory);
		//self::$APP_path = pathinfo(realpath( $appDirectory), PATHINFO_DIRNAME);//pathinfo($_SERVER["SCRIPT_FILENAME"], PATHINFO_DIRNAME);

		//加载常用方法
		include self::$YYK_path. DIRECTORY_SEPARATOR . 'common.php';

		if (file_exists(self::$APP_path. DIRECTORY_SEPARATOR . 'common.php')) {
			//加载项目自定义方法
			include self::$APP_path. DIRECTORY_SEPARATOR . 'common.php';
		}
		//加载默认配置
		/*
		$tmp = array();
		if (file_exists(self::$YYK_path. DIRECTORY_SEPARATOR . 'config.php')) {
		$tmp = include self::$YYK_path. DIRECTORY_SEPARATOR . 'config.php';
		}
		*/

		//加载用户配置
		$conf = empty($conf) ? "config.php" : $conf;
		if (file_exists(self::$APP_path. DIRECTORY_SEPARATOR . $conf)){
			self::$config = include self::$APP_path. DIRECTORY_SEPARATOR . $conf;
		}

		//合并配置
		/*
		self::$config = array_merge($tmp, self::$config);
		unset($tmp);
		*/

		// 注册AUTOLOAD方法
		//加载用户控制器类
		spl_autoload_register(array('YYK', 'appCtrl'));

		//加载用户模型类
		spl_autoload_register(array('YYK', 'appModel'));

		//加载YYK核心类
		spl_autoload_register(array('YYK', 'YYKClass'));

		//加载框架扩展类

		//加载第三方类
		spl_autoload_register(array('YYK', 'otherClass'));

		//启动session
		session_start();

		//设置时区
		date_default_timezone_set(self::$config['timeZone']);

		//启用smart static server 智能选择静态服务器
		/**/
		if (isset(self::$config['cacheRedis']) && count(self::$config['cacheRedis'])>0 && isset(self::$config['s3']) && count(self::$config['s3'])>0){
			$mem = CacheRedis::create();
			$s3_key = 's3_' . ip2long(getIp());
			$country = $mem->get($s3_key);

			if (!$country) {
				if($ipInfo = getIpInfo(getIP())){
					$country = $ipInfo['country_id'];
				}
			}

			if (isset(self::$config['s3'][$country]) && is_array(self::$config['s3'][$country]) ) {
				self::$config['tplConst'] =array_merge( self::$config['tplConst'], self::$config['s3'][$country]);
			}

			$mem->set($s3_key, $country);
			$mem->expire($s3_key, 600);
		}
		
		//路由分析
		$requestRoute = self::parseRoute();
		self::$ctrlName = $requestRoute[0];
		self::$methodName = $requestRoute[1];

		//启用语言包
		if (isset(self::$config['useMultiLang']) && self::$config['useMultiLang']==true ) {
			if (isset($_GET['l'])) {
				setLang($_GET['l']);
				self::$defaultLang = $_GET['l'];
			}
			else{
				setLang(getLang());
				self::$defaultLang = getLang();
			}
		}


		//检查是否开启了模板静态缓存
		$staticCacheRoute = strstr($_SERVER['REQUEST_URI'], self::$ctrlName . DIRECTORY_SEPARATOR . self::$methodName);
		$staticCacheType = false;

		if (isset( self::$config['staticCache'][$staticCacheRoute] )) {
			$staticCacheType = $staticCacheType = isset(self::$config['staticCacheType']) ? self::$config['staticCacheType'] : 'FS';

			$staticCacheKey = 'staticCache' . str_replace(DIRECTORY_SEPARATOR, '_', self::$APP_path) . str_replace(DIRECTORY_SEPARATOR, '_', $staticCacheRoute);
			
			header('Server: Microsoft-IIS/8.0');
			header('X-Powered-By: ASP.NET');
			$content ='';
			switch(strtolower($staticCacheType)) {
				case 'redis':
					$redis = CacheRedis::create();
					$cacheTtl = $redis->ttl($staticCacheKey);
					$cacheTtl = $cacheTtl>0 ? $cacheTtl : 0;
					$cacheModifyTime   = time() -( self::$config['staticCache'][$staticCacheRoute] - $cacheTtl);
					$requestModifyTime= isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])-3600*8 : 0 ;
					$cacheExpire = $cacheModifyTime + self::$config['staticCache'][$staticCacheRoute];
					if ($cacheExpire > time()) {
						if ($cacheModifyTime <= $requestModifyTime ) {
							header("HTTP/1.1 304 Not Modified");
							header("Date: " . date('D, d M Y H:i:s', time()) . ' GMT');
							header("Last-Modified: " . date('D, d M Y H:i:s', $cacheModifyTime) . ' GMT');
							header("Cache-Control: max-age=" . $cacheTtl);
							header("Expires: ".date('D, d M Y H:i:s', $cacheExpire) . ' GMT');
							exit(0);
						}
						$content = $redis->get($staticCacheKey);
					}
					break;

				case 'memcache':
					$memcache = CacheMem::create();
					$content =  $memcache->get($staticCacheKey);
					$cacheModifyTime = substr($content, 0, strpos($content, ','));
					$cacheTtl = self::$config['staticCache'][$staticCacheRoute] - ( time()-$cacheModifyTime );
					$cacheTtl = $cacheTtl>0 ? $cacheTtl : 0;
					$requestModifyTime= isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])-3600*8 : 0 ;
					$cacheExpire = $cacheModifyTime + self::$config['staticCache'][$staticCacheRoute];
					if ($cacheExpire > time()) {
						if ($cacheModifyTime <= $requestModifyTime ) {
							header("HTTP/1.1 304 Not Modified");
							header("Date: " . date('D, d M Y H:i:s', time()) . ' GMT');
							header("Last-Modified: " . date('D, d M Y H:i:s', $cacheModifyTime) . ' GMT');
							header("Cache-Control: max-age=" . $cacheTtl);
							header("Expires: ".date('D, d M Y H:i:s', $cacheExpire) . ' GMT');
							exit(0);
						}
						$content = substr($content, strpos($content, ',')+1);
					}
					break;

				default:	//默认文件系统缓存
					$tplCache = self::$APP_path . DIRECTORY_SEPARATOR . 'html' . DIRECTORY_SEPARATOR . self::$ctrlName . DIRECTORY_SEPARATOR . self::$methodName . '.html';
					if (!file_exists($tplCache)) {
						break;
					}
					$cacheModifyTime = filemtime($tplCache);
					$cacheTtl = self::$config['staticCache'][$staticCacheRoute] - ( time()-$cacheModifyTime );
					$cacheTtl = $cacheTtl>0 ? $cacheTtl : 0;
					$requestModifyTime= isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])-3600*8 : 0 ;
					$cacheExpire = $cacheModifyTime + self::$config['staticCache'][$staticCacheRoute];
					//echo $cacheModifyTime . "<br>";
					//echo $requestModifyTime . "<br>";
					//echo time();
					if ($cacheExpire > time()) {
						if ($cacheModifyTime <= $requestModifyTime ) {
							header("HTTP/1.1 304 Not Modified");
							header("Date: " . date('D, d M Y H:i:s', time()) . ' GMT');
							header("Last-Modified: " . date('D, d M Y H:i:s', $cacheModifyTime) . ' GMT');
							header("Cache-Control: max-age=" . $cacheTtl);
							header("Expires: ".date('D, d M Y H:i:s', $cacheExpire) . ' GMT');
							exit(0);
						}
						else{
							$content = file_get_contents($tplCache);
						}
					}

					break;
			}

			if (strlen($content)>0) {
				header("Date: " . date('D, d M Y H:i:s', time()) . ' GMT');
				header("Last-Modified: " . date('D, d M Y H:i:s', $cacheModifyTime) . ' GMT');
				header("Cache-Control: max-age=" . $cacheTtl);
				header("Expires: ".date('D, d M Y H:i:s', $cacheExpire) . ' GMT');
				echo $content;exit(0);
			}
		}
		self::$ctrlName = $requestRoute[0] . 'Ctrl';

		//检查路由是否存在
		if (class_exists(self::$ctrlName)){
			$C = new self::$ctrlName();
			if (method_exists($C, self::$methodName)){
				self::$ctrlName = $requestRoute[0];
				call_user_func(array($C, self::$methodName));
			}
			else{
				//E( 'None method:'.self::$methodName);
				_404();
			}
		}
		else{
			//控制器不存在
			//E( 'None Controller:' . self::$ctrlName);
			_404();
		}
	}

	/**
	* 自动加载用户控制器类库
	* 并且支持配置自动加载路径
	* @param string $class 对象类名
	* @return void
	*/
	public static function appCtrl($class){
		if (file_exists(self::$APP_path . DIRECTORY_SEPARATOR . 'Ctrl' . DIRECTORY_SEPARATOR . $class . '.class.php')) {
			include_once(self::$APP_path . DIRECTORY_SEPARATOR . 'Ctrl' . DIRECTORY_SEPARATOR  .$class . '.class.php');
		}
	}

	/**
	* 自动加载用户模型类库
	* 并且支持配置自动加载路径
	* @param string $class 对象类名
	* @return void
	*/
	public static function appModel($class){
		if (file_exists(self::$APP_path . DIRECTORY_SEPARATOR . 'Model' . DIRECTORY_SEPARATOR . $class . '.class.php')) {
			include_once(self::$APP_path . DIRECTORY_SEPARATOR . 'Model' . DIRECTORY_SEPARATOR  . $class . '.class.php');
		}
	}

	public static function YYKClass($class){
		$class = strtolower($class);
		if (file_exists(self::$YYK_path . DIRECTORY_SEPARATOR . $class . '.class.php')) {
			include_once(self::$YYK_path . DIRECTORY_SEPARATOR . $class . '.class.php');
		}
	}

	public static function otherClass($class){
		if (file_exists(self::$YYK_path . DIRECTORY_SEPARATOR . 'lib'. DIRECTORY_SEPARATOR . $class . DIRECTORY_SEPARATOR . $class . '.class.php')) {
			include_once(self::$YYK_path . DIRECTORY_SEPARATOR . 'lib'. DIRECTORY_SEPARATOR . $class . DIRECTORY_SEPARATOR . $class . '.class.php');
		}
		else{
			if (substr($class, -4) == 'Ctrl') {
				//_404();
			}
			else{
				E('Not Found Class: '.$class);
			}
		}
	}

	//路由分析
	public static function parseRoute(){
		if (isset($_GET['s']) && strlen($_GET['s'])>0){
			$_SERVER['PATH_INFO'] = $_GET['s'];
		}

		if (isset($_SERVER['PATH_INFO']) && strlen($_SERVER['PATH_INFO'])>1){
			$pathInfo = $_SERVER['PATH_INFO'];
			if (isset(YYK::$config['urlFix'])) {
				if (substr($pathInfo, 0- strlen(YYK::$config['urlFix'])) == YYK::$config['urlFix']) {
					$pathInfo = substr($pathInfo, 0, 0- strlen(YYK::$config['urlFix']));
				}
			}
			$pathInfo = trim($pathInfo, '/');

			$arr = explode(self::$config['pathinfoSeparator'], trim($pathInfo, '/'));

			if (self::$config['switchRoute'] && count($arr)>0){
				//检查是否在路由定义中

				//精确匹配
				$tmp = preg_grep("/^{$arr[0]}$/", array_keys(self::$config['routeRule']));
				//模糊匹配
				$tmp2 = preg_grep("/^{$arr[0]}:/", array_keys(self::$config['routeRule']));

				if (count($arr)==1){	//路由规则无参数
					if (count($tmp)>0) {//精确匹配
						return self::$config['routeRule'][$tmp[0]];
					}
					if (count($tmp2)>0) {
						foreach ($tmp2 as $key => $value) {
							$param = explode(':', $value);
							echo count($param) .','. count($arr) .';';
							if (count($param) == count($arr)) {
								return self::$config['routeRule'][$value];
							}
						}

						foreach ($tmp2 as $key => $value) {
							return self::$config['routeRule'][$value];
						}
					}
				}

				if (count($arr) > 1){	//带参数
					if (count($tmp2)>0) {
						foreach ($tmp2 as $key => $value) {
							$param = explode(':', $value);
							if (count($param) == count($arr)) {
								for ($i=1; ; $i++) {
									if(!isset($arr[$i])) break;
									$_GET[$param[$i]] = $arr[$i];
								}                                
								return self::$config['routeRule'][$value];
							}
						}
						foreach ($tmp2 as $key => $value) {
							for ($i=1; ; $i++) {
								if(!isset($arr[$i])) break;
								$_GET[$param[$i]] = $arr[$i];
							}
							return self::$config['routeRule'][$value];
						}
					}

					if (count($tmp)>0) {//精确匹配
						return self::$config['routeRule'][$tmp[0]];
					}
				}
			}
			//pathinfo非路由
			if ((!isset($arr[0])) || strlen($arr[0])==0) {
				$arr[0] = 'Index';
			}
			if ((!isset($arr[1])) || strlen($arr[1])==0) {
				$arr[1] = 'index';
			}
			for ($i=2; ; $i+=2) {
				if(!isset($arr[$i])) break;
				$_GET[$arr[$i]] = $arr[$i+1];
			}
			return array($arr[0], $arr[1]);
		}
		else{	//非pathinfo模式
			if (isset($_GET['c']))
				$c = $_GET['c'];
			else
				$c = 'Index';
			if (isset($_GET['m']))
				$m = $_GET['m'];
			else
				$m = 'index';
			return array($c, $m);
		}
	}

	public static function appError($fehlercode, $fehlertext, $fehlerdatei, $fehlerzeile){
		if (self::$debug) {
			echo "<b>Custom error:</b> [$fehlercode] $fehlertext";
			echo " Error on line $fehlerzeile in $fehlerdatei<br />";
		}
		return true;
	}

	public static function appException($exception){
		if (self::$debug) {
			echo "Uncaught exception: " , $exception->getMessage(), "<br>";
		}
		return true;
	}

	public static function getYYK_path(){
		return self::$YYK_path;
	}
}

//其他:验证码,文件上传,Excel,分页